﻿namespace MicroCloud.Authorization
{
    /// <summary>
    /// 权限服务
    /// </summary>
    public class AuthorityService : IAuthorityService
    {
        /// <summary>
        /// 初始化一个权限服务 <see cref="AuthorityService"/> 的新实例
        /// </summary>
        /// <param name="serviceProvider">服务提供者</param>
        public AuthorityService(IServiceProvider serviceProvider)
        {
            ServiceProvider = serviceProvider;
        }

        #region "属性"
        #region "获取 服务提供者"
        /// <summary>
        /// 获取 服务提供者
        /// </summary>
        protected IServiceProvider ServiceProvider { get; }
        #endregion
        #region "获取 日志记录器"
        /// <summary>
        /// 获取 日志记录器
        /// </summary>
        protected ILogger Logger => ServiceProvider.GetLogger(GetType());
        #endregion
        #region "获取 功能权限缓存"
        /// <summary>
        /// 获取 功能权限缓存
        /// </summary>
        protected IFunctionAuthCache FunctionAuthCache => ServiceProvider.GetRequiredService<IFunctionAuthCache>();
        #endregion
        #region "获取 模块信息处理器"
        /// <summary>
        /// 获取 模块信息处理器
        /// </summary>
        protected IModuleHandler ModuleHandler => ServiceProvider.GetRequiredService<IModuleHandler>();
        #endregion
        #region "获取 功能权限验证"
        /// <summary>
        /// 获取 功能权限验证
        /// </summary>
        protected IFunctionAuthorization FunctionAuthorization => ServiceProvider.GetRequiredService<IFunctionAuthorization>();
        #endregion
        #region "获取 当前用户的基本功能"
        /// <summary>
        /// 获取 当前用户的基本功能
        /// </summary>
        protected IPrincipal Principal => ServiceProvider.GetService<IPrincipal>();
        #endregion

        #region "获取 用户角色仓储"
        /// <summary>
        /// 获取 用户角色仓储
        /// </summary>
        protected IRepository<UserRole, long> UserRoleRepository => ServiceProvider.GetRequiredService<IRepository<UserRole, long>>();
        #endregion
        #region "获取 用户角色信息集合"
        /// <summary>
        /// 获取 用户角色信息集合
        /// </summary>
        protected IQueryable<UserRole> UserRoles => UserRoleRepository.QueryAsNoTracking();
        #endregion

        #region "获取 角色仓储"
        /// <summary>
        /// 获取 角色仓储
        /// </summary>
        protected IRepository<Role, long> RoleRepository => ServiceProvider.GetRequiredService<IRepository<Role, long>>();
        #endregion
        #region "获取 角色信息集合"
        /// <summary>
        /// 获取 角色信息集合
        /// </summary>
        protected IQueryable<Role> Roles => RoleRepository.QueryAsNoTracking();
        #endregion

        #endregion

        #region "方法"
        #region "获取指定用户已授权模块信息"
        /// <summary>
        /// 获取指定用户已授权模块信息
        /// </summary>
        /// <param name="principal">在线用户信息</param>
        /// <returns>模块信息集合</returns>
        public virtual List<ModuleInfo> GetAuthorizedInfosByUser(IPrincipal principal = null)
        {
            List<ModuleInfo> authorizedInfos = new();
            var User = principal ?? Principal;
            if (User == null)
            {
                return authorizedInfos;
            }
            ModuleInfo[] moduleInfos = ModuleHandler.ModuleInfos;

            //先查找出所有有权限的模块
            List<ModuleInfo> authModules = new();
            foreach (ModuleInfo moduleInfo in moduleInfos)
            {
                bool hasAuth = moduleInfo.DependOnFunctions.All(m => FunctionAuthorization.Authorize(m, User).IsOk);
                if (moduleInfo.DependOnFunctions.Length == 0 || hasAuth)
                {
                    authModules.Add(moduleInfo);
                }
            }
            foreach (ModuleInfo moduleInfo in authModules)
            {
                string fullCode = moduleInfo.FullCode;
                //模块下边有功能，或者拥有子模块
                if (moduleInfo.DependOnFunctions.Length > 0 || authModules.Any(m => m.FullCode.Length > fullCode.Length && m.FullCode.Contains(fullCode) && m.DependOnFunctions.Length > 0))
                {
                    authorizedInfos.AddIfNotExist(moduleInfo, e => authorizedInfos.Exists(o => o.FullCode == e.FullCode));
                }
            }
            return authorizedInfos;
        }
        #endregion
        #region "获取指定用户已授权模块信息"
        /// <summary>
        /// 获取指定用户已授权模块信息
        /// </summary>
        /// <param name="userId">用户编号</param>
        /// <returns>模块信息集合</returns>
        public virtual List<ModuleInfo> GetAuthorizedInfosByUser(string userId)
        {
            List<ModuleInfo> authorizedInfos = new();
            if (userId.IsMissing())
            {
                return authorizedInfos;
            }
            ModuleInfo[] moduleInfos = ModuleHandler.ModuleInfos;

            //先查找出所有有权限的模块
            List<ModuleInfo> authModules = new();
            //用户角色
            var userRoles = UserRoles.Where(w => w.UserId == userId.CastTo<long>()).Select(o => new OnlineRole { Id = o.RoleId.ToString(), Name = o.Role.Name, Remark = o.Role.Remark, IsAdmin = o.Role.IsAdmin }).ToArray();
            foreach (ModuleInfo moduleInfo in moduleInfos)
            {
                bool hasAuth = moduleInfo.DependOnFunctions.All(m => Authorize(m, userId, userRoles).IsOk);
                if (moduleInfo.DependOnFunctions.Length == 0 || hasAuth)
                {
                    authModules.Add(moduleInfo);
                }
            }
            foreach (ModuleInfo moduleInfo in authModules)
            {
                string fullCode = moduleInfo.FullCode;
                //模块下边有功能，或者拥有子模块
                if (moduleInfo.DependOnFunctions.Length > 0 || authModules.Any(m => m.FullCode.Length > fullCode.Length && m.FullCode.Contains(fullCode) && m.DependOnFunctions.Length > 0))
                {
                    authorizedInfos.AddIfNotExist(moduleInfo, e => authorizedInfos.Exists(o => o.FullCode == e.FullCode));
                }
            }
            return authorizedInfos;
        }
        #endregion
        #region "获取指定角色已授权模块信息"
        /// <summary>
        /// 获取指定角色已授权模块信息
        /// </summary>
        /// <param name="roleId">角色编号</param>
        /// <returns>模块信息集合</returns>
        public virtual List<ModuleInfo> GetAuthorizedInfosByRole(string roleId)
        {
            List<ModuleInfo> authorizedInfos = new();
            if (roleId.IsMissing())
            {
                return authorizedInfos;
            }
            ModuleInfo[] moduleInfos = ModuleHandler.ModuleInfos;


            //先查找出所有有权限的模块
            List<ModuleInfo> authModules = new();
            //角色
            var roles = Roles.Where(w => w.Id == roleId.CastTo<long>()).Select(o => new OnlineRole { Id = o.Id.ToString(), Name = o.Name, Remark = o.Remark, IsAdmin = o.IsAdmin }).ToArray();
            foreach (ModuleInfo moduleInfo in moduleInfos)
            {
                bool hasAuth = moduleInfo.DependOnFunctions.All(m => AuthorizeRoles(m, roles).IsOk);
                if (moduleInfo.DependOnFunctions.Length == 0 || hasAuth)
                {
                    authModules.Add(moduleInfo);
                }
            }
            foreach (ModuleInfo moduleInfo in authModules)
            {
                string fullCode = moduleInfo.FullCode;
                //模块下边有功能，或者拥有子模块
                if (moduleInfo.DependOnFunctions.Length > 0 || authModules.Any(m => m.FullCode.Length > fullCode.Length && m.FullCode.Contains(fullCode) && m.DependOnFunctions.Length > 0))
                {
                    authorizedInfos.AddIfNotExist(moduleInfo, e => authorizedInfos.Exists(o => o.FullCode == e.FullCode));
                }
            }
            return authorizedInfos;
        }
        #endregion

        #endregion

        #region "受保护的方法"
        #region "检查指定用户是否有执行指定功能的权限"
        /// <summary>
        /// 检查指定用户是否有执行指定功能的权限
        /// </summary>
        /// <param name="function">要检查的功能</param>
        /// <param name="userId">用户编号</param>
        /// <param name="userRoles">用户角色集合</param>
        /// <returns>功能权限检查结果</returns>
        protected virtual AuthorizationResult Authorize(IFunction function, string userId, params OnlineRole[] userRoles)
        {
            if (function == null)
            {
                return new AuthorizationResult(AuthorizationStatus.NoFound);
            }
            if (function.IsLocked)
            {
                return new AuthorizationResult(AuthorizationStatus.Locked, I18N.T("功能 {0} 已禁用", function.Name));
            }
            if (function.AccessType == FunctionAccessType.Anonymous)
            {
                return AuthorizationResult.OK;
            }
            //未登录
            if (userId.IsMissing())
            {
                return new AuthorizationResult(AuthorizationStatus.Unauthorized);
            }
            //已登录，无角色限制
            if (function.AccessType == FunctionAccessType.LoggedIn)
            {
                return AuthorizationResult.OK;
            }
            return AuthorizeRoleLimit(function, userId, userRoles);
        }
        #endregion
        #region "角色限制的功能的功能权限检查"
        /// <summary>
        /// 角色限制的功能的功能权限检查
        /// </summary>
        /// <param name="function">要验证的功能信息</param>
        /// <param name="userId">用户编号</param>
        /// <param name="userRoles">用户角色集合</param>
        /// <returns>功能权限验证结果</returns>
        protected virtual AuthorizationResult AuthorizeRoleLimit(IFunction function, string userId, params OnlineRole[] userRoles)
        {
            //未登录
            if (userId.IsMissing())
            {
                return new AuthorizationResult(AuthorizationStatus.Unauthorized);
            }
            //检查角色-功能的权限
            AuthorizationResult result = AuthorizeRoles(function, userRoles);
            if (result.IsOk)
            {
                return result;
            }
            result = AuthorizeUser(function, userId);
            return result;
        }
        #endregion
        #region "重写以实现指定角色是否有执行指定功能的权限"
        /// <summary>
        /// 重写以实现指定角色是否有执行指定功能的权限
        /// </summary>
        /// <param name="function">功能信息</param>
        /// <param name="userRoles">用户角色集合</param>
        /// <returns>功能权限检查结果</returns>
        protected virtual AuthorizationResult AuthorizeRoles(IFunction function, params OnlineRole[] userRoles)
        {
            Check.NotNull(userRoles, nameof(userRoles));

            if (userRoles.Length == 0)
            {
                return new AuthorizationResult(AuthorizationStatus.Forbidden);
            }
            if (function.AccessType != FunctionAccessType.RoleLimit || userRoles.Any(o => o.IsAdmin))
            {
                return AuthorizationResult.OK;
            }
            string[] functionRoleIds = FunctionAuthCache.GetFunctionRoles(function.Id);
            if (userRoles.Any(o => functionRoleIds.Contains(o.Id)))
            {
                return AuthorizationResult.OK;
            }
            return new AuthorizationResult(AuthorizationStatus.Forbidden);
        }
        #endregion
        #region "重写以实现指定用户是否有执行指定功能的权限"
        /// <summary>
        /// 重写以实现指定用户是否有执行指定功能的权限
        /// </summary>
        /// <param name="function">功能信息</param>
        /// <param name="userId">用户编号</param>
        /// <returns>功能权限检查结果</returns>
        protected virtual AuthorizationResult AuthorizeUser(IFunction function, string userId)
        {
            if (function.AccessType != FunctionAccessType.RoleLimit)
            {
                return AuthorizationResult.OK;
            }

            var functionIds = FunctionAuthCache.GetUserFunctions(userId);
            if (functionIds.Contains(function.Id))
            {
                return AuthorizationResult.OK;
            }
            return new AuthorizationResult(AuthorizationStatus.Forbidden);
        }
        #endregion

        #endregion

    }
}
